package lightswitch.server.code.datahelper;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.Vector;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import lightswitch.server.code.object.*;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * @author HieuPT
 */
public class XMLManagement {
    public static Document doc;
    static final BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

    public static boolean loadXML(String path) {
        try {
            File fXmlFile = new File(path);
            DocumentBuilderFactory dbFac = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFac.newDocumentBuilder();
            doc = dBuilder.parse(fXmlFile);
            doc.getDocumentElement().normalize();
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public static boolean saveData(String path) {
        // TODO Auto-generated method stub
        try {
            // Prepare the DOM document for writing
            Source source = new DOMSource(doc.getDocumentElement());

            // Prepare the output file
            File file = new File(path);
            Result result = new StreamResult(file);

            // Write the DOM document to the file
            Transformer xformer = TransformerFactory.newInstance().newTransformer();
            xformer.transform(source, result);
            return true;
        } catch (TransformerConfigurationException e) {
            return false;
        } catch (TransformerException e) {
            return false;
        }

    }

    public static boolean addNewTable(Table tb, String databaseName) {
        Element databaseEle = getDatabaseElement(databaseName);
        if (databaseEle == null)
            return false;
        
        if ("".equals(tb.getName()))
            return false;

        Element eleTable = Table.createElement(doc, tb);
        databaseEle.appendChild(eleTable);
        return true;

    }

    public static boolean dropTable(String tbName, String databaseName) {        
        Element databaseEle = getDatabaseElement(databaseName);
        if (databaseEle == null)
            return false;
        NodeList noteList = databaseEle.getChildNodes();
        for (int i = 0; i < noteList.getLength(); i++) {
            Node node = noteList.item(i);
            String _str = "";
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                Element ele = (Element) (node);
                _str += ele.getAttribute("name");
                if (tbName.equals(_str)) {
                    Node parentNode = node.getParentNode();
                    parentNode.removeChild(node);
                    return true;
                }
            }
        }

        return false;
    }

    public static boolean dropDatabase(String databaseName) {
        if ("".equals(databaseName) || databaseName.equals("_default"))
            return false;
        
        Element databaseEle = getDatabaseElement(databaseName);
        if (databaseEle == null)
            return false;
        
        Node parent = databaseEle.getParentNode();
        parent.removeChild(databaseEle);
        return true;
    }

    
    public static boolean editTable(String tbName, Table newTable) {
        String databaseName = newTable.getDatabaseName();
        Element databaseEle = getDatabaseElement(databaseName);
        if (databaseEle == null)
            return false;
        NodeList noteList = databaseEle.getChildNodes();
        
        for (int i = 0; i < noteList.getLength(); i++) {
            Node node = noteList.item(i);
            String _str = "";
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                Element ele = (Element) (node);
                _str += ele.getAttribute("name");
                if (tbName.equals(_str)) {
                    Node parentNode = node.getParentNode();
                    parentNode.removeChild(node);
                    parentNode.appendChild(Table.createElement(doc, newTable));
                    return true;
                }
            }
        }

        return false;
    }

    public static Vector<Table> getListOfTables(String databaseName) {
        Vector<Table> vectorTable = new Vector<Table>();
        Vector<String> tableNames = getListStringOfTableName(databaseName);
        if (tableNames!=null){
            for (String s : tableNames) {
                Table tb = XMLManagement.getTable(s, databaseName);
                if (tb != null)
                    vectorTable.add(tb);
            }
        }
        
        return vectorTable;

    }
    
    public static Vector<Object> getListOfTableName(String databaseName) {
        Element databaseEle = getDatabaseElement(databaseName);
        if (databaseEle == null)
            return null;
        Vector<Object> vectorData = new Vector<Object>();
        NodeList noteList = databaseEle.getChildNodes();
        for (int i = 0; i < noteList.getLength(); i++) {
            Node node = noteList.item(i);
            String _str = "";
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                Element ele = (Element) (node);
                _str += ele.getAttribute("name");
                vectorData.add(_str);
            }
        }

        return vectorData;

    }

    public static Vector<String> getListStringOfTableName(String databaseName) {
        Element databaseEle = getDatabaseElement(databaseName);
        if (databaseEle == null)
            return null;
        Vector<String> vectorData = new Vector<String>();
        NodeList noteList = databaseEle.getChildNodes();
        for (int i = 0; i < noteList.getLength(); i++) {
            Node node = noteList.item(i);
            String _str = "";
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                Element ele = (Element) (node);
                _str += ele.getAttribute("name");
                vectorData.add(_str);
            }
        }

        return vectorData;

    }

    public static Vector<Object> getHierarchyTableName(String databaseName) {
        
        Element databaseEle = getDatabaseElement(databaseName);
        if (databaseEle == null)
            return null;
        Vector<Object> vectorData = new Vector<Object>();
        vectorData.add(databaseName);
        NodeList nodeList = databaseEle.getChildNodes();
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);
            String _str = "";
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                Element ele = (Element) (node);
                _str += ele.getAttribute("name");
                vectorData.add(_str);
            }
        }

        return vectorData;

    }

    public static Table getTable(String tbName, String databaseName) {
        Element databaseEle = getDatabaseElement(databaseName);
        if (databaseEle == null || "".equals(tbName))
            return null;
        NodeList noteList = databaseEle.getChildNodes();
        for (int i = 0; i < noteList.getLength(); i++) {
            Node node = noteList.item(i);
            String _str = "";
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                Element ele = (Element) (node);
                _str += ele.getAttribute("name");
                if (tbName.equals(_str)) {
                    // XXX
                    return Table.createTableFromNode(ele);
                    //
                }
            }
        }
        return null;
    }

    public static void mergeTables(Vector<Table> editedTables, String databaseName) {
        
        Vector<String> originDatanames = getListStringOfTableName(databaseName);
        
        for (Table editedTable : editedTables) {
            if (isExistInVector(editedTable.getName(),originDatanames)){
                XMLManagement.editTable(editedTable.getName(), editedTable);
            } else{
                XMLManagement.addNewTable(editedTable, databaseName);
            }
        }
        
        Vector<String> editedTableNames = Table.getVectorNameFromVectorTable(editedTables);
        
        for (String originName: originDatanames){
            if (!isExistInVector(originName, editedTableNames)){
                dropTable(originName, databaseName);
            }
        }
        
    }
    
    public static Element getDatabaseElement(String databaseName){
        NodeList noteList = doc.getElementsByTagName("TABLES");
        for (int i = 0; i < noteList.getLength(); i++) {
            Node node = noteList.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                Element ele = (Element) (node);
                if (ele.getAttribute("name").equals(databaseName)){
                    return ele;
                }
            }
        }
        return null;
    }
    
    public static Object[] getListOfDatabaseNames(){
        Vector<Object> result = new Vector<Object>();
        NodeList noteList = doc.getElementsByTagName("TABLES");
        for (int i = 0; i < noteList.getLength(); i++) {
            Node node = noteList.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                Element ele = (Element) (node);
                result.add(ele.getAttribute("name"));
            }
        }
        return result.toArray();
    }
    
    
    public static Vector<String> getVectorOfDatabaseNames(){
        Vector<String> result = new Vector<String>();
        NodeList noteList = doc.getElementsByTagName("TABLES");
        for (int i = 0; i < noteList.getLength(); i++) {
            Node node = noteList.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                Element ele = (Element) (node);
                result.add(ele.getAttribute("name"));
            }
        }
        return result;
    }

    public static void addNewDatabase(String databaseName) {
        Element tablesEle = doc.createElement("TABLES");
        tablesEle.setAttribute("name", databaseName);
        doc.getFirstChild().appendChild(tablesEle);
    }
    
    public static boolean isExistInVector(String name, Vector<String> names){
        for (String c : names){
            if (name.equals(c))
                return true;
        }
        return false;
    }
}
